/*
* Author: Chris Seguin
*
* This software has been developed under the copyleft
* rules of the GNU General Public License. Please
* consult the GNU General Public License for more
* details about use and distribution of this software.
*/
package org.acm.seguin.refactor.type;
import java.util.Iterator;
import java.util.LinkedList;
import org.acm.seguin.summary.MethodSummary;
import org.acm.seguin.summary.TypeDeclSummary;
import org.acm.seguin.summary.TypeSummary;
import org.acm.seguin.summary.query.GetTypeSummary;
/**
* This class searches the type heirarchy looking for abstract methods that
* have not yet been instantiated. Abstract methods are gathered into a
* linked list. <P>
*
* This object is used by CreateClass to build a list of abstract methods
* that the user will have to overload.
*
*@author Chris Seguin
*/
public class AbstractMethodFinder {
private LinkedList list;
private TypeSummary leaf;
/**
* Constructor for the AbstractMethodFinder object
*
*@param init the type summary
*/
public AbstractMethodFinder(TypeSummary init)
{
leaf = init;
list = new LinkedList();
load();
}
/**
* Constructor for the AbstractMethodFinder object used for unit testing
*
*@param init the type summary
*@param testing dummy variable
*/
AbstractMethodFinder(TypeSummary init, boolean testing)
{
leaf = init;
list = new LinkedList();
}
/**
* Gets the List attribute of the AbstractMethodFinder object
*
*@return The List value
*/
public LinkedList getList()
{
return list;
}
/**
* Loads the interface methods
*/
void loadInterfaceMethods()
{
TypeSummary current = leaf;
while (current != null) {
// Get the interfaces
Iterator iter = current.getImplementedInterfaces();
if (iter != null) {
while (iter.hasNext()) {
TypeDeclSummary nextDecl = (TypeDeclSummary) iter.next();
TypeSummary nextType = GetTypeSummary.query(nextDecl);
loadInterface(nextType);
}
}
current = nextType(current);
}
}
/**
* Removes those methods which have been instantiated (and adds abstract
* methods). Uses recursive processing to traverse through the parent
* classes first.
*
*@param current The current type summary
*/
void filter(TypeSummary current)
{
if (current == null) {
return;
}
// Visit parent first
TypeSummary next = nextType(current);
filter(next);
// Consider each method of the current
Iterator iter = current.getMethods();
if (iter != null) {
while (iter.hasNext()) {
MethodSummary nextMethod = (MethodSummary) iter.next();
if (nextMethod.getModifiers().isAbstract()) {
add(nextMethod);
}
else {
removeImplementations(nextMethod);
}
}
}
}
/**
* Loads the interface methods and then filters out those that have been
* instatiated
*/
private void load()
{
loadInterfaceMethods();
filter(leaf);
}
/**
* Loads a particular interface type summary
*
*@param type the interface
*/
private void loadInterface(TypeSummary type)
{
if (type == null) {
return;
}
Iterator iter = type.getMethods();
if (iter != null) {
while (iter.hasNext()) {
add((MethodSummary) iter.next());
}
}
iter = type.getImplementedInterfaces();
if (iter != null) {
while (iter.hasNext()) {
TypeDeclSummary nextDecl = (TypeDeclSummary) iter.next();
TypeSummary nextType = GetTypeSummary.query(nextDecl);
loadInterface(nextType);
}
}
}
/**
* Gets the next type - finds the parent class type summary
*
*@param current the current type summary
*@return the parent type summary
*/
private TypeSummary nextType(TypeSummary current)
{
return GetTypeSummary.query(current.getParentClass());
}
/**
* Removes the implementation of a particular method from the linked list
*
*@param methodSummary the method whose signature we can remove
*/
private void removeImplementations(MethodSummary methodSummary)
{
Iterator iter = list.iterator();
while (iter.hasNext()) {
MethodSummary next = (MethodSummary) iter.next();
if (methodSummary.checkSignature(next)) {
iter.remove();
}
}
}
/**
* Adds a method summary
*
*@param methodSummary the method whose signature we want to add
*/
private void add(MethodSummary methodSummary)
{
Iterator iter = list.iterator();
while (iter.hasNext()) {
MethodSummary next = (MethodSummary) iter.next();
if (methodSummary.checkSignature(next)) {
return;
}
}
list.add(methodSummary);
}
}